package com.czk.shop.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.comon.czk.constant.ShopCode;
import com.comon.czk.entity.Result;
import com.comon.czk.exception.CastException;
import com.comon.czk.utils.IDWorker;
import com.czk.api.IPayService;
import com.czk.shop.mapper.TradeMqProducerTempMapper;
import com.czk.shop.mapper.TradePayMapper;
import com.czk.shop.pojo.TradeMqProducerTemp;
import com.czk.shop.pojo.TradePay;
import com.czk.shop.pojo.TradePayExample;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.Objects;

/**
 *
 * @Author:ChenZhangKun
 * @Date: 2020/11/7 16:31
 */
@Component
@Slf4j
@Service(interfaceClass = IPayService.class)
public class PayServiceImpl implements IPayService {
    @Value("${rocketmq.producer.group}")
    private String groupName;
    @Value("${mq.topic}")
    private String topic;
    @Value("${mq.pay.tag}")
    private String tag;
    @Autowired
    private TradePayMapper tradePayMapper;
    @Autowired
    private IDWorker idWorker;
    @Autowired
    private TradeMqProducerTempMapper tradeMqProducerTempMapper;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Override
    public Result createPayment(TradePay tradePay) {
        // 校验参数
        if (tradePay==null||tradePay.getOrderId()==null){
            CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);
        }
        // 1 判断订单支付状态
        TradePayExample example=new TradePayExample();
        example.createCriteria()
                .andOrderIdEqualTo(tradePay.getOrderId())
                .andIsPaidEqualTo(ShopCode.SHOP_PAYMENT_IS_PAID.getCode());
        int i = tradePayMapper.countByExample(example);
        if (i>0){
            // 订单有支付记录
            // 没必要再支付
            CastException.cast(ShopCode.SHOP_PAYMENT_IS_PAID);
        }
        // 2 设置订单状态为未支付
        tradePay.setIsPaid(ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY.getCode());
        // 3 保存支付订单
        tradePay.setPayId(idWorker.nextId());
        tradePayMapper.insert(tradePay);
        return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage());
    }

    @Override
    public Result callbackPayment(TradePay tradePay) {
        // 1 判断用户支付状态
        if (tradePay.getIsPaid().intValue()==ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode().intValue()){
            // 2 更新订单状态为已支付
            Long payId = tradePay.getPayId();
            TradePay pay = tradePayMapper.selectByPrimaryKey(payId);
            if (pay==null){
                CastException.cast(ShopCode.SHOP_PAYMENT_NOT_FOUND);
            }
            // 更改为已支付
            pay.setIsPaid(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode());
            // 更新数据哭
            int i = tradePayMapper.updateByPrimaryKey(pay);
            if (i==1){
                // 更新成功
                TradeMqProducerTemp tradeMqProducerTemp=new TradeMqProducerTemp();
                // 生成id
                tradeMqProducerTemp.setId(String.valueOf(idWorker.nextId()));
                // 3 创建支付成功的消息
                // topic
                tradeMqProducerTemp.setMsgTopic(topic);
                tradeMqProducerTemp.setMsgTag(tag);
                tradeMqProducerTemp.setGroupName(groupName);
                // 业务表示
                tradeMqProducerTemp.setMsgKey(String.valueOf(tradePay.getPayId()));
                // messgaeBody
                tradeMqProducerTemp.setMsgBody(JSON.toJSONString(tradePay));
                tradeMqProducerTemp.setCreateTime(new Date());
                // 4 将消息持久化到数据库
                tradeMqProducerTempMapper.insert(tradeMqProducerTemp);
                threadPoolTaskExecutor.submit(()->{
                    try {
                        // 5 发送消息到mq
                        SendResult sendResult=this.sendMessage(topic,tag,tradePay.getPayId(),JSON.toJSONString(tradePay));
                        if (Objects.equals(sendResult.getSendStatus(), SendStatus.SEND_OK)){
                            log.info("消息发送成功");
                            // 6 等待发送结果，如果mq接收了消息，则删除消息
                            tradeMqProducerTempMapper.deleteByPrimaryKey(tradeMqProducerTemp.getId());
                        }
                    }catch (Exception ex){
                        log.error("消息发送失败");
                        CastException.cast(ShopCode.SHOP_MQ_SEND_MESSAGE_FAIL);
                    }
                });

            }
        }
        return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage());
    }

    /**
     * 发送支付成功的消息
     * @param topic topic
     * @param tag tag
     * @param payId key
     * @param toJSONString body
     */
    private SendResult sendMessage(String topic, String tag, Long payId, String toJSONString) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
        // 校验参数
        if (StringUtils.isEmpty(topic)){
            CastException.cast(ShopCode.SHOP_MQ_TOPIC_IS_EMPTY);
        }
        if (StringUtils.isEmpty(toJSONString)){
            CastException.cast(ShopCode.SHOP_MQ_MESSAGE_BODY_IS_EMPTY);
        }
        // 创建message对象
        Message message=new Message(topic,tag,String.valueOf(payId),toJSONString.getBytes());
        // 发送消息
        SendResult send = rocketMQTemplate.getProducer().send(message);
        return send;
    }
}
